home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / larn.lha / monster.c < prev    next >
C/C++ Source or Header  |  1995-11-19  |  22KB  |  652 lines

  1. /*
  2.  *  monster.c
  3.  *
  4.  *  createmonster(monstno)      Function to create a monster next to the player
  5.  *      int monstno;
  6.  *
  7.  *  int cgood(x,y,itm,monst)    Function to check location for emptiness
  8.  *      int x,y,itm,monst;
  9.  *
  10.  *  createitem(it,arg)          Routine to place an item next to the player
  11.  *      int it,arg;
  12.  *
  13.  *  vxy(x,y)            Routine to verify/fix (*x,*y) for being within bounds
  14.  *      int *x,*y;
  15.  *
  16.  *  hitmonster(x,y)     Function to hit a monster at the designated coordinates
  17.  *      int x,y;
  18.  *
  19.  *  hitm(x,y,amt)       Function to just hit a monster at a given coordinates
  20.  *      int x,y,amt;
  21.  *
  22.  *  hitplayer(x,y)      Function for the monster to hit the player from (x,y)
  23.  *      int x,y;
  24.  *
  25.  *  dropsomething(monst)    Function to create an object when a monster dies
  26.  *      int monst;
  27.  *
  28.  *  dropgold(amount)        Function to drop some gold around player
  29.  *      int amount;
  30.  *
  31.  *  something(level)        Function to create a random item around player
  32.  *      int level;
  33.  *
  34.  *  newobject(lev,i)        Routine to return a randomly selected new object
  35.  *      int lev,*i;
  36.  *
  37.  *  spattack(atckno,xx,yy)  Function to process special attacks from monsters
  38.  *      int atckno,xx,yy;
  39.  *
  40.  *  checkloss(x)    Routine to subtract hp from user and flag bottomline display
  41.  *      int x;
  42.  *
  43.  */
  44. #include "header.h"
  45. #include "larndefs.h"
  46. #include "monsters.h"
  47. #include "objects.h"
  48. #include "player.h"
  49.  
  50. #include <ctype.h>
  51. #define min(x,y) (((x)>(y))?(y):(x))
  52. #define max(x,y) (((x)>(y))?(x):(y))
  53.  
  54. extern fullhit(), ifblind();
  55.  
  56. /*
  57.  *  createmonster(monstno)      Function to create a monster next to the player
  58.  *      int monstno;
  59.  *
  60.  *  Enter with the monster number (1 to MAXMONST+8)
  61.  *  Returns no value.
  62.  */
  63. createmonster(mon)
  64.     int mon;
  65.     {
  66.     register int x,y,k,i;
  67.     if (mon<1 || mon>MAXMONST+8)    /* check for monster number out of bounds */
  68.         {
  69.         beep(); lprintf("\ncan't createmonst(%d)\n",(long)mon); nap(3000); return;
  70.         }
  71.     while (monster[mon].genocided && mon<MAXMONST) mon++; /* genocided? */
  72.     for (k=rnd(8), i= -8; i<0; i++,k++) /* choose direction, then try all */
  73.         {
  74.         if (k>8) k=1;   /* wraparound the diroff arrays */
  75.         x = playerx + diroffx[k];       y = playery + diroffy[k];
  76.         if (cgood(x,y,0,1)) /* if we can create here */
  77.             {
  78.             mitem[x][y] = mon;
  79.             hitp[x][y] = monster[mon].hitpoints;
  80.             stealth[x][y]=0;
  81.             know[x][y] &= ~KNOWHERE;
  82.             switch(mon)
  83.                 {
  84.                 case ROTHE: case POLTERGEIST: case VAMPIRE: stealth[x][y]=1;
  85.                 };
  86.             return;
  87.             }
  88.         }
  89.     }
  90.  
  91. /*
  92.  *  int cgood(x,y,itm,monst)      Function to check location for emptiness
  93.  *      int x,y,itm,monst;
  94.  *
  95.  *  Routine to return TRUE if a location does not have itm or monst there
  96.  *  returns FALSE (0) otherwise
  97.  *  Enter with itm or monst TRUE or FALSE if checking it
  98.  *  Example:  if itm==TRUE check for no item at this location
  99.  *            if monst==TRUE check for no monster at this location
  100.  *  This routine will return FALSE if at a wall,door or the dungeon exit
  101.  *  on level 1
  102.  */
  103. static int cgood(x,y,itm,monst)
  104.     register int x,y;
  105.     int itm,monst;
  106.     {
  107.     /* cannot create either monster or item if:
  108.        - out of bounds
  109.        - wall
  110.        - closed door
  111.        - dungeon entrance
  112.     */
  113.     if (((y < 0) || (y > MAXY-1) || (x < 0) || (x > MAXX-1)) ||
  114.          (item[x][y] == OWALL) ||
  115.          (item[x][y] == OCLOSEDDOOR) ||
  116.          ((level == 1) && (x == 33) && (y == MAXY-1)))
  117.         return( FALSE );
  118.  
  119.     /* if checking for an item, return False if one there already
  120.     */
  121.     if ( itm && item[x][y])
  122.         return( FALSE );
  123.  
  124.     /* if checking for a monster, return False if one there already _or_
  125.        there is a pit/trap there.
  126.     */
  127.     if (monst)
  128.         {
  129.         if (mitem[x][y])
  130.             return (FALSE);
  131.         switch(item[x][y])
  132.             {
  133.             /* note: not invisible traps, since monsters are not affected
  134.                by them.
  135.             */
  136.             case OPIT:         case OANNIHILATION:
  137.             case OTELEPORTER:  case OTRAPARROW:
  138.             case ODARTRAP:    case OTRAPDOOR:
  139.                 return(FALSE);
  140.                 break;
  141.             default:
  142.                 break;
  143.             }
  144.         }
  145.     return(TRUE);
  146.     }
  147.  
  148. /*
  149.  *  createitem(it,arg)      Routine to place an item next to the player
  150.  *      int it,arg;
  151.  *
  152.  *  Enter with the item number and its argument (iven[], ivenarg[])
  153.  *  Returns no value, thus we don't know about createitem() failures.
  154.  */
  155. createitem(it,arg)
  156.     int it,arg;
  157.     {
  158.     register int x,y,k,i;
  159.     if (it >= MAXOBJ) return;   /* no such object */
  160.     for (k=rnd(8), i= -8; i<0; i++,k++) /* choose direction, then try all */
  161.         {
  162.         if (k>8) k=1;   /* wraparound the diroff arrays */
  163.         x = playerx + diroffx[k];       y = playery + diroffy[k];
  164.         if (cgood(x,y,1,0)) /* if we can create here */
  165.             {
  166.             item[x][y] = it;  know[x][y]=0;  iarg[x][y]=arg;  return;
  167.             }
  168.         }
  169.     }
  170.  
  171.  
  172. /*
  173.  *  vxy(x,y)       Routine to verify/fix coordinates for being within bounds
  174.  *      int *x,*y;
  175.  *
  176.  *  Function to verify x & y are within the bounds for a level
  177.  *  If *x or *y is not within the absolute bounds for a level, fix them so that
  178.  *    they are on the level.
  179.  *  Returns TRUE if it was out of bounds, and the *x & *y in the calling
  180.  *  routine are affected.
  181.  */
  182. vxy(x,y)
  183.     int *x,*y;
  184.     {
  185.     int flag=0;
  186.     if (*x<0) { *x=0; flag++; }
  187.     if (*y<0) { *y=0; flag++; }
  188.     if (*x>=MAXX) { *x=MAXX-1; flag++; }
  189.     if (*y>=MAXY) { *y=MAXY-1; flag++; }
  190.     return(flag);
  191.     }
  192.  
  193. /*
  194.  *  hitmonster(x,y)     Function to hit a monster at the designated coordinates
  195.  *      int x,y;
  196.  *
  197.  *  This routine is used for a bash & slash type attack on a monster
  198.  *  Enter with the coordinates of the monster in (x,y).
  199.  *  Returns no value.
  200.  */
  201. hitmonster(x,y)
  202.     int x,y;
  203.     {
  204.     extern char lastmonst[] ;
  205.     register int tmp,monst,damag,flag;
  206.     if (c[TIMESTOP])  return;  /* not if time stopped */
  207.     vxy(&x,&y); /* verify coordinates are within range */
  208.     if ((monst = mitem[x][y]) == 0) return;
  209.     hit3flag=1;  ifblind(x,y);
  210.     tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS]/4 - 12;
  211.     cursors();
  212.     if ((rnd(20) < tmp-c[HARDGAME]) || (rnd(71) < 5)) /* need at least random chance to hit */
  213.         {
  214.         lprcat("\nYou hit");  flag=1;
  215.         damag = fullhit(1);
  216.         if (damag<9999) damag=rnd(damag)+1;
  217.         }
  218.     else
  219.         {
  220.         lprcat("\nYou missed");  flag=0;
  221.         }
  222.     lprcat(" the "); lprcat(lastmonst);
  223.     if (flag)   /* if the monster was hit */
  224.       if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
  225.         if (c[WIELD]>=0)
  226.           if (ivenarg[c[WIELD]] > -10)
  227.             {
  228.             lprintf("\nYour weapon is dulled by the %s",lastmonst); beep();
  229.             --ivenarg[c[WIELD]];
  230.  
  231.             /* fix for dulled rings of strength,cleverness, and dexterity
  232.                bug.
  233.             */
  234.             switch (iven[c[WIELD]])
  235.                 {
  236.                 case ODEXRING :
  237.                     c[DEXTERITY]--;
  238.                     break;
  239.                 case OSTRRING :
  240.                     c[STREXTRA]--;
  241.                     break;
  242.                 case OCLEVERRING :
  243.                     c[INTELLIGENCE]--;
  244.                     break;
  245.                 }
  246.             }
  247.     if (flag)  hitm(x,y,damag);
  248.     if (monst == VAMPIRE) if (hitp[x][y]<25)  { mitem[x][y]=BAT; know[x][y]=0; }
  249.     }
  250.  
  251. /*
  252.  *  hitm(x,y,amt)       Function to just hit a monster at a given coordinates
  253.  *      int x,y,amt;
  254.  *
  255.  *  Returns the number of hitpoints the monster absorbed
  256.  *  This routine is used to specifically damage a monster at a location (x,y)
  257.  *  Called by hitmonster(x,y)
  258.  */
  259. hitm(x,y,amt)
  260.     int x,y;
  261.     register amt;
  262.     {
  263.     extern char lastmonst[] ;
  264.     register int monst;
  265.     int hpoints,amt2;
  266.     vxy(&x,&y); /* verify coordinates are within range */
  267.     amt2 = amt;     /* save initial damage so we can return it */
  268.     monst = mitem[x][y];
  269.     if (c[HALFDAM]) amt >>= 1;  /* if half damage curse adjust damage points */
  270.     if (amt<=0) amt2 = amt = 1;
  271.     lasthx=x;  lasthy=y;
  272.     stealth[x][y]=1;    /* make sure hitting monst breaks stealth condition */
  273.     c[HOLDMONST]=0; /* hit a monster breaks hold monster spell  */
  274.     switch(monst) /* if a dragon and orb(s) of dragon slaying   */
  275.         {
  276.         case WHITEDRAGON:       case REDDRAGON:         case GREENDRAGON:
  277.         case BRONZEDRAGON:      case PLATINUMDRAGON:    case SILVERDRAGON:
  278.             amt *= 1+(c[SLAYING]<<1);   break;
  279.         }
  280. /* invincible monster fix is here */
  281.     if (hitp[x][y] > monster[monst].hitpoints)
  282.         hitp[x][y] = monster[monst].hitpoints;
  283.     if ((hpoints = hitp[x][y]) <= amt)
  284.         {
  285. #ifdef EXTRA
  286.         c[MONSTKILLED]++;
  287. #endif
  288.         lprintf("\nThe %s died!",lastmonst);
  289.         raiseexperience((long)monster[monst].experience);
  290.         amt = monster[monst].gold;  if (amt>0) dropgold(rnd(amt)+amt);
  291.         dropsomething(monst);   disappear(x,y); bottomline();
  292.         return(hpoints);
  293.         }
  294.     hitp[x][y] = hpoints-amt;   return(amt2);
  295.     }
  296.  
  297. /*
  298.  *  hitplayer(x,y)      Function for the monster to hit the player from (x,y)
  299.  *      int x,y;
  300.  *
  301.  *  Function for the monster to hit the player with monster at location x,y
  302.  *  Returns nothing of value.
  303.  */
  304. hitplayer(x,y)
  305.     int x,y;
  306.     {
  307.     extern char lastmonst[] ;
  308.     register int dam,tmp,mster,bias;
  309.     vxy(&x,&y); /* verify coordinates are within range */
  310.     lastnum = mster = mitem[x][y];
  311. /*  spirit naga's and poltergeist's do nothing if scarab of negate spirit   */
  312.     if (c[NEGATESPIRIT] || c[SPIRITPRO])  if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA))  return;
  313. /*  if undead and cube of undead control    */
  314.     if (c[CUBEofUNDEAD] || c[UNDEADPRO]) if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) return;
  315.     if ((know[x][y] & KNOWHERE) == 0)
  316.         show1cell(x,y);
  317.     bias = (c[HARDGAME]) + 1;
  318.     hitflag = hit2flag = hit3flag = 1;
  319.     yrepcount=0;
  320.     cursors();  ifblind(x,y);
  321.     if (c[INVISIBILITY]) if (rnd(33)<20) 
  322.         {
  323.         lprintf("\nThe %s misses wildly",lastmonst);    return;
  324.         }
  325.     if (c[CHARMCOUNT]) if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30)
  326.         {
  327.         lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
  328.         return;
  329.         }
  330.     if (mster==BAT) dam=1;
  331.     else
  332.         {
  333.         dam = monster[mster].damage;
  334.         dam += rnd((int)((dam<1)?1:dam)) + monster[mster].level;
  335.         }
  336.     tmp = 0;
  337.     if (monster[mster].attack>0)
  338.       if (((dam + bias + 8) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
  339.         { if (spattack(monster[mster].attack,x,y)) { lflushall(); return; }
  340.           tmp = 1;  bias -= 2; cursors(); }
  341.     if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1))
  342.         {
  343.         lprintf("\n  The %s hit you ",lastmonst);   tmp = 1;
  344.         if ((dam -= c[AC]) < 0) dam=0;
  345.         if (dam > 0) { losehp(dam); bottomhp(); lflushall(); }
  346.         }
  347.     if (tmp == 0)  lprintf("\n  The %s missed ",lastmonst);
  348.     }
  349.  
  350. /*
  351.  *  dropsomething(monst)    Function to create an object when a monster dies
  352.  *      int monst;
  353.  *
  354.  *  Function to create an object near the player when certain monsters are killed
  355.  *  Enter with the monster number
  356.  *  Returns nothing of value.
  357.  */
  358. static dropsomething(monst)
  359.     int monst;
  360.     {
  361.     switch(monst)
  362.         {
  363.         case ORC:             case NYMPH:      case ELF:      case TROGLODYTE:
  364.         case TROLL:           case ROTHE:      case VIOLETFUNGI:
  365.         case PLATINUMDRAGON:  case GNOMEKING:  case REDDRAGON:
  366.             something(level); return;
  367.  
  368.         case LEPRECHAUN: if (rnd(101)>=75) creategem();
  369.                          if (rnd(5)==1) dropsomething(LEPRECHAUN);   return;
  370.         }
  371.     }
  372.  
  373. /*
  374.  *  dropgold(amount)    Function to drop some gold around player
  375.  *      int amount;
  376.  *
  377.  *  Enter with the number of gold pieces to drop
  378.  *  Returns nothing of value.
  379.  */
  380. dropgold(amount)
  381.     register int amount;
  382.     {
  383.     if (amount > 250) 
  384.         createitem(OMAXGOLD,amount/100);  
  385.     else  
  386.         createitem(OGOLDPILE,amount);
  387.     }
  388.  
  389. /*
  390.  *  something(level)    Function to create a random item around player
  391.  *      int level;
  392.  *
  393.  *  Function to create an item from a designed probability around player
  394.  *  Enter with the cave level on which something is to be dropped
  395.  *  Returns nothing of value.
  396.  */
  397. something(level)
  398.     int level;
  399.     {
  400.     register int j;
  401.     int i;
  402.     if (level<0 || level>MAXLEVEL+MAXVLEVEL) return;    /* correct level? */
  403.     if (rnd(101)<8)
  404.         something(level); /* possibly more than one item */
  405.     j = newobject(level,&i);
  406.     createitem(j,i);
  407.     }
  408.  
  409. /*
  410.  *  newobject(lev,i)    Routine to return a randomly selected new object
  411.  *      int lev,*i;
  412.  *
  413.  *  Routine to return a randomly selected object to be created
  414.  *  Returns the object number created, and sets *i for its argument
  415.  *  Enter with the cave level and a pointer to the items arg
  416.  */
  417. static char nobjtab[] = { 0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
  418.     OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE,
  419.     OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
  420.     OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
  421.     OBELT, ORING, OSTUDLEATHER, OSHIELD, OCOOKIE, OFLAIL, OCHAIN, OBATTLEAXE,
  422.     OSPLINT, O2SWORD, OCLEVERRING, OPLATE, OLONGSWORD };
  423.  
  424. newobject(lev,i)
  425.     register int lev,*i;
  426.     {
  427.     register int tmp=33,j;
  428.     if (level<0 || level>MAXLEVEL+MAXVLEVEL) return(0); /* correct level? */
  429.     if (lev>6) tmp=41; else if (lev>4) tmp=39;
  430.     j = nobjtab[tmp=rnd(tmp)];  /* the object type */
  431.     switch(tmp)
  432.         {
  433.         case 1: case 2: case 3: case 4:  /* scroll */
  434.             *i=newscroll(); break;
  435.         case 5: case 6: case 7: case 8:  /* potion */
  436.             *i=newpotion(); break;
  437.         case 9: case 10: case 11: case 12:  /* gold */
  438.             *i=rnd((lev+1)*10)+lev*10+10; break;
  439.         case 13: case 14: case 15: case 16:  /* book */
  440.             *i=lev; break;
  441.         case 17: case 18: case 19:   /* dagger */
  442.             if (!(*i=newdagger()))  return(0);  break;
  443.         case 20: case 21: case 22:   /* leather armor */
  444.             if (!(*i=newleather()))  return(0);  break;
  445.         case 23: case 32: case 38:   /* regen ring, shield, 2-hand sword */
  446.             *i=rund(lev/3+1); break;
  447.         case 24: case 26:            /* prot ring, dexterity ring */
  448.             *i=rnd(lev/4+1);   break;
  449.         case 25:                     /* energy ring */
  450.             *i=rund(lev/4+1); break;
  451.         case 27: case 39:            /* strength ring, cleverness ring */
  452.             *i=rnd(lev/2+1);   break;
  453.         case 30: case 34:           /* ring mail, flail */
  454.             *i=rund(lev/2+1);   break;
  455.         case 28: case 36:           /* spear, battleaxe */
  456.             *i=rund(lev/3+1); if (*i==0) return(0); break;
  457.         case 29: case 31: case 37:  /* belt, studded leather, splint */
  458.             *i=rund(lev/2+1); if (*i==0) return(0); break;
  459.         case 33:                    /* fortune cookie */
  460.             *i=0; break;
  461.         case 35:                    /* chain mail */
  462.             *i=newchain();     break;
  463.         case 40:                    /* plate mail */
  464.             *i=newplate();     break;
  465.         case 41:                    /* longsword */
  466.             *i=newsword();     break;
  467.         }
  468.     return(j);
  469.     }
  470.  
  471. /*
  472.  *  spattack(atckno,xx,yy)  Function to process special attacks from monsters
  473.  *      int atckno,xx,yy;
  474.  *
  475.  *  Enter with the special attack number, and the coordinates (xx,yy)
  476.  *      of the monster that is special attacking
  477.  *  Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
  478.  *
  479.  * atckno   monster     effect
  480.  * ---------------------------------------------------
  481.  *  0   none
  482.  *  1   rust monster    eat armor
  483.  *  2   hell hound      breathe light fire
  484.  *  3   dragon          breathe fire
  485.  *  4   giant centipede weakening sing
  486.  *  5   white dragon    cold breath
  487.  *  6   wraith          drain level
  488.  *  7   waterlord       water gusher
  489.  *  8   leprechaun      steal gold
  490.  *  9   disenchantress  disenchant weapon or armor
  491.  *  10  ice lizard      hits with barbed tail
  492.  *  11  umber hulk      confusion
  493.  *  12  spirit naga     cast spells taken from special attacks
  494.  *  13  platinum dragon psionics
  495.  *  14  nymph           steal objects
  496.  *  15  bugbear         bite
  497.  *  16  osequip         bite
  498.  *
  499.  *  char rustarm[ARMORTYPES][2];
  500.  *  special array for maximum rust damage to armor from rustmonster
  501.  *  format is: { armor type , minimum attribute 
  502.  */
  503. #define ARMORTYPES 6
  504. #if __STDC__
  505. static signed char rustarm[ARMORTYPES][2] =
  506. #else
  507. static char rustarm[ARMORTYPES][2] =
  508. #endif
  509.     { OSTUDLEATHER,-2, ORING,      -4,
  510.       OCHAIN,      -5, OSPLINT,    -6,
  511.       OPLATE,      -8, OPLATEARMOR,-9  };
  512. static char spsel[] = { 1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
  513. static spattack(x,xx,yy)
  514.     int x,xx,yy;
  515.     {
  516.     extern char lastmonst[] ;
  517.     register int i,j=0,k,m;
  518.     register char *p=0;
  519.     if (c[CANCELLATION]) return(0);
  520.     vxy(&xx,&yy);   /* verify x & y coordinates */
  521.     switch(x)
  522.         {
  523.         case 1: /* rust your armor, j=1 when rusting has occurred */
  524.                 m = k = c[WEAR];
  525.                 if ((i=c[SHIELD]) != -1)
  526.                     if (--ivenarg[i] < -1) ivenarg[i]= -1; else j=1;
  527.                 if ((j==0) && (k != -1))
  528.                   {
  529.                   m = iven[k];
  530.                   for (i=0; i<ARMORTYPES; i++)
  531.                     if (m == rustarm[i][0]) /* find his armor in table */
  532.                         {
  533.                         if (--ivenarg[k]< rustarm[i][1])
  534.                             ivenarg[k]= rustarm[i][1]; else j=1; 
  535.                         break;
  536.                         }
  537.                   }
  538.                 if (j==0)   /* if rusting did not occur */
  539.                   switch(m)
  540.                     {
  541.                     case OLEATHER:  p = "\nThe %s hit you -- Your lucky you have leather on";
  542.                                     break;
  543.                     case OSSPLATE:  p = "\nThe %s hit you -- Your fortunate to have stainless steel armor!";
  544.                                     break;
  545.                     }
  546.                 else  { beep(); p = "\nThe %s hit you -- your armor feels weaker"; }
  547.                 break;
  548.  
  549.         case 2:     i = rnd(15)+8-c[AC];
  550.             spout:  p="\nThe %s breathes fire at you!";
  551.                     if (c[FIRERESISTANCE])
  552.                       p="\nThe %s's flame doesn't phase you!";
  553.                     else
  554.             spout2: if (p) { lprintf(p,lastmonst); beep(); }
  555.                     checkloss(i);
  556.                     return(0);
  557.  
  558.         case 3:     i = rnd(20)+25-c[AC];  goto spout;
  559.  
  560.         case 4: if (c[STRENGTH]>3)
  561.                     {
  562.                     p="\nThe %s stung you!  You feel weaker"; beep();
  563.                     --c[STRENGTH];
  564.                     }
  565.                 else p="\nThe %s stung you!";
  566.                 break;
  567.  
  568.         case 5:     p="\nThe %s blasts you with his cold breath";
  569.                     i = rnd(15)+18-c[AC];  goto spout2;
  570.  
  571.         case 6:     lprintf("\nThe %s drains you of your life energy!",lastmonst);
  572.                     loselevel();  beep();  return(0);
  573.  
  574.         case 7:     p="\nThe %s got you with a gusher!";
  575.                     i = rnd(15)+25-c[AC];  goto spout2;
  576.  
  577.         case 8:     if (c[NOTHEFT]) return(0); /* he has a device of no theft */
  578.                     if (c[GOLD])
  579.                         {
  580.                         p="\nThe %s hit you -- Your purse feels lighter";
  581.                         if (c[GOLD]>32767)  c[GOLD]>>=1;
  582.                             else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
  583.                         if (c[GOLD] < 0) c[GOLD]=0;
  584.                         }
  585.                     else  p="\nThe %s couldn't find any gold to steal";
  586.                     lprintf(p,lastmonst); disappear(xx,yy); beep();
  587.                     bottomgold();  return(1);
  588.  
  589.         case 9: for(j=50; ; )   /* disenchant */
  590.                     {
  591.                     i=rund(26);  m=iven[i]; /* randomly select item */
  592.                     if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
  593.                         {
  594.                         if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
  595.                         lprintf("\nThe %s hits you -- you feel a sense of loss",lastmonst);
  596.                         beep(); show3(i);  bottomline();  return(0);
  597.                         }
  598.                     if (--j<=0)
  599.                         {
  600.                         p="\nThe %s nearly misses"; break;
  601.                         }
  602.                     break;
  603.                     }       
  604.                 break;
  605.  
  606.         case 10:   p="\nThe %s hit you with his barbed tail";
  607.                    i = rnd(25)-c[AC];  goto spout2;
  608.  
  609.         case 11:    p="\nThe %s has confused you"; beep();
  610.                     c[CONFUSE]+= 10+rnd(10);        break;
  611.  
  612.         case 12:    /*  performs any number of other special attacks    */
  613.                     return(spattack(spsel[rund(10)],xx,yy));
  614.  
  615.         case 13:    p="\nThe %s flattens you with his psionics!";
  616.                     i = rnd(15)+30-c[AC];  goto spout2;
  617.  
  618.         case 14:    if (c[NOTHEFT]) return(0); /* he has device of no theft */
  619.                     if (emptyhanded()==1)
  620.                       {
  621.                       p="\nThe %s couldn't find anything to steal";
  622.                       break;
  623.                       }
  624.                     lprintf("\nThe %s picks your pocket and takes:",lastmonst);
  625.                     beep();
  626.                     if (stealsomething()==0) lprcat("  nothing"); disappear(xx,yy);
  627.                     bottomline();  return(1);
  628.  
  629.         case 15:    i= rnd(10)+ 5-c[AC];
  630.             spout3: p="\nThe %s bit you!";
  631.                     goto spout2;
  632.  
  633.         case 16:    i= rnd(15)+10-c[AC];  goto spout3;
  634.         };
  635.     if (p) { lprintf(p,lastmonst); bottomline(); }
  636.     return(0);
  637.     }
  638.  
  639. /*
  640.  *  checkloss(x)    Routine to subtract hp from user and flag bottomline display
  641.  *      int x;
  642.  *
  643.  *  Routine to subtract hitpoints from the user and flag the bottomline display
  644.  *  Enter with the number of hit points to lose
  645.  *  Note: if x > c[HP] this routine could kill the player!
  646.  */
  647. checkloss(x)
  648.     int x;
  649.     {
  650.     if (x>0) { losehp(x);  bottomhp(); }
  651.     }
  652.